/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2024-05-03 08:50:42
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2024-05-04 10:16:37
 * @FilePath: /pipe/processpool/myprocesspool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <unistd.h>
#include <ctime>
#include <sys/wait.h>
#include "mytask.hpp"

using namespace std;

enum
{
    UsageError = 1,
    ArgError,
    PipeError
};
void Usage(const std::string &proc)
{
    cout << "Usage: " << proc << " subprocess-num" << endl;
}

class Channel
{
public:
    Channel(int wfd, pid_t sub_id, string &name)
        : _wfd(wfd), _sub_process_id(sub_id), _name(name)
    {
    }
    ~Channel()
    {}
    string getname()
    {
        return _name;
    }
    int getwfd()
    {
        return _wfd;
    }
    int getpid()
    {
        return _sub_process_id;
    }
    void printDebug()
    {
        cout << "_wfd: " << _wfd;
        cout << ",_sub_process_id: " << _sub_process_id;
        cout << ", _name: " << _name << endl;
    }
    void Close()
    {
        close(_wfd);
    }
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};
class ProcessPool
{
public:
    ProcessPool(int sub_process_nums) : _sub_process_nums(sub_process_nums)
    {
    }
    int CreateProcess(work_t work)//回调函数
    {
        //保存父进程的写端--》解决一个bug：父进程写端很多时，子进城会删不干净(关一个回收一个)
        vector<int> fds;
        for (int number = 0; number < _sub_process_nums; number++)
        {
            int pipefd[2]{0}; // 创建匿名管道(每次创建不同的管道)
            int n = pipe(pipefd);
            if (n < 0)
                return PipeError;

            pid_t id = fork(); // 创建进程
            if (id < 0)
                return 1;
            else if (id == 0)
            {
                if (!fds.empty())   //使关闭父进程的写端
                {
                    std::cout << "close wfd: ";
                    for (auto fd : fds)
                    {
                        close(fd);
                        std::cout << fd << " ";
                    }
                    std::cout << std::endl;
                }
                // child  -> r
                close(pipefd[1]); // 关闭写端
                dup2(pipefd[0],0);
                work(pipefd[0]);
                exit(0);
            }
            string cname = "channel-" + to_string(number);
            // father -> w
            close(pipefd[0]);
            channels.push_back(Channel(pipefd[1], id, cname));
           fds.push_back(pipefd[1]);
        } 
        return 0;
    } 
     //bug----->当写端很多时，会删不干净，便会一直阻塞等待
    void KillAll()
    {
        for(auto &channel:channels)
        {
            channel.Close();
            pid_t pid=channel.getpid();
            pid_t rid=waitpid(pid,nullptr,0);
            if(pid==rid)
            {
                cout<<"wait sub_process "<<pid<<" success..."<<endl;
            }
            std::cout << channel.getname() << " close done" << " sub process quit now : " << channel.getpid() << std::endl;
        }
    }
    //可以与KillAll进行组合
    // void Wait()
    // {
    //     for(auto &channel:channels)
    //     {
    //         pid_t pid=channel.getpid();
    //         pid_t rid=waitpid(pid,nullptr,0);
    //         if(pid==rid)
    //             cout<<"wait sub_process "<<pid<<" success..."<<endl;
    //     }
    // }
    int NextChannel()
    {
        static int next=0;
        int c=next++;
        next%=channels.size();
        return c;
    }
    void SendTaskCode(int index, uint32_t code)
    {
        cout << "send code: " << code << " to " << channels[index].getname() << " sub prorcess id: " <<  channels[index].getpid() << endl;
        write(channels[index].getwfd(), &code, sizeof(code));
    }
    void Debug()
    {
        for (auto &cl : channels)
        {
            cl.printDebug();
        }
    }
    ~ProcessPool()
    { }

private:
    int _sub_process_nums;
    vector<Channel> channels;
};
void CtrlProcesspool(ProcessPool*processpool_ptr,int cnt)
{
     while(cnt)
    {
        //1.选择一个管道和进程
        int channel=processpool_ptr->NextChannel();
        sleep(1);
        //2.选择一个任务
        uint32_t TaskCode=NextTask();
        //3.发送任务
        processpool_ptr->SendTaskCode(channel, TaskCode);
        sleep(1);
        cnt--;
    }
}
int main(int argc, char *argv[]) // 输入性参数
{

    srand((uint64_t)time(nullptr));//随机数种子
    if (argc != 2) // argc是输入参数的个数，argv是输入参数的值
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_nums = stoi(argv[1]); // 子进程个数
    if (sub_process_nums <= 0)
        return ArgError;

    //vector<Channel> channels; // 用vector储存
    // 1.创建通信管道和子进程
    ProcessPool *processpool_ptr=new ProcessPool(sub_process_nums);
    processpool_ptr->CreateProcess(worker);
   // processpool_ptr->Debug();
    // 2.控制子进程
   CtrlProcesspool(processpool_ptr,10);
    // 3.回收子进程
    //a.让所有子进程退出
    processpool_ptr->KillAll();
    //b.让所有退出子进程进行资源回收
    //processpool_ptr->Wait();
    // wait  sub_process
    delete processpool_ptr;
    return 0;
}